package org.loon.framework.android.game.core.graphics.opengl;

import java.nio.FloatBuffer;
import java.util.HashMap;

import org.loon.framework.android.game.core.LRelease;
import org.loon.framework.android.game.core.LSystem;
import org.loon.framework.android.game.core.geom.Matrix.Transform2D;
import org.loon.framework.android.game.core.graphics.LColor;
import org.loon.framework.android.game.core.graphics.opengl.LTexture.Format;
import org.loon.framework.android.game.core.graphics.opengl.GL;
import org.loon.framework.android.game.core.graphics.opengl.GL10;
import org.loon.framework.android.game.core.graphics.opengl.GLEx;
import org.loon.framework.android.game.core.graphics.opengl.LTexture;
import org.loon.framework.android.game.core.graphics.opengl.LTextureBatch;
import org.loon.framework.android.game.core.graphics.opengl.LTextures;
import org.loon.framework.jni.NativeSupport;

/**
 * Copyright 2008 - 2011
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
/**
 * 此类专为批量渲染单一纹理而设置（比如处理海量精灵块，地图块等），允许提交缓存中数据到渲染器
 * @project loonframework
 * @author chenpeng
 * @email：ceponline@yahoo.com.cn
 * @version 0.1
 */
// 此类专为批量渲染单一纹理而设置（比如处理海量精灵块，地图块等），允许提交缓存中数据到渲染器
public final class LTextureBatch implements LRelease {

	static boolean isBatchCacheDitry;

	private final static HashMap<Integer, LTextureBatch> batchPools = new HashMap<Integer, LTextureBatch>(
			10);

	public final static void clearBatchCaches() {
		if (LTextureBatch.isBatchCacheDitry) {
			HashMap<Integer, LTextureBatch> batchCaches;
			synchronized (batchPools) {
				batchCaches = new HashMap<Integer, LTextureBatch>(batchPools);
				batchPools.clear();
			}
			for (LTextureBatch bt : batchCaches.values()) {
				if (bt != null) {
					synchronized (bt) {
						bt.dispose();
						bt = null;
					}
				}
			}
			batchCaches = null;
			LTextureBatch.isBatchCacheDitry = false;
		}
	}

	public final static LTextureBatch bindBatchCache(final LTexture texture) {
		return bindBatchCache(0, texture);
	}

	public final static LTextureBatch bindBatchCache(final int index,
			final LTexture texture) {
		if (texture == null) {
			return null;
		}
		int texId = texture.textureID;
		return bindBatchCache(index, texId, texture);
	}

	public final static LTextureBatch bindBatchCache(final Object o,
			final int texId, final LTexture texture) {
		return bindBatchCache(o.hashCode(), texId, texture);
	}

	public final static LTextureBatch bindBatchCache(final int index,
			final int texId, final LTexture texture) {
		if (batchPools.size() > 128) {
			clearBatchCaches();
		}
		int key = LSystem.unite(index, texId);
		LTextureBatch pBatch = batchPools.get(key);
		if (pBatch == null) {
			synchronized (batchPools) {
				pBatch = new LTextureBatch(texture);
				batchPools.put(key, pBatch);
			}
		}
		return pBatch;
	}

	public final static LTextureBatch disposeBatchCache(int texId) {
		synchronized (batchPools) {
			LTextureBatch pBatch = batchPools.remove(texId);
			if (pBatch != null) {
				synchronized (pBatch) {
					pBatch.dispose();
					pBatch = null;
				}
			}
			return pBatch;
		}
	}

	private GLCache lastCache;

	private LColor[] colors;

	private Transform2D transform;

	public static class GLCache implements LRelease {

		FloatBuffer vertexBuffer;

		FloatBuffer coordsBuffer;

		FloatBuffer colorBuffer;

		public float x, y;

		int count;

		boolean isColor;

		public GLCache(LTextureBatch batch) {
			this(batch, true);
		}

		public GLCache(LTextureBatch batch, boolean reset) {

			if (reset) {
				batch.insertVertices();
			}

			this.count = batch.count;
			this.isColor = batch.isColor;

			vertexBuffer = NativeSupport.newFloatBuffer(batch.verts, 0,
					batch.oldVertCount);
			
			if (isColor) {
				colorBuffer = NativeSupport.newFloatBuffer(batch.cols, 0,
						batch.oldColorCount);
			}

			coordsBuffer = NativeSupport.newFloatBuffer(batch.coords, 0,
					batch.oldCoordCount);


			this.x = batch.moveX;
			this.y = batch.moveY;
		}

		public void flip() {
			if (vertexBuffer != null) {
				vertexBuffer.flip();
			}
			if (coordsBuffer != null) {
				coordsBuffer.flip();
			}
			if (colorBuffer != null) {
				colorBuffer.flip();
			}
		}

		public void limit(int size) {
			if (vertexBuffer != null) {
				vertexBuffer.limit(size);
			}
			if (coordsBuffer != null) {
				coordsBuffer.limit(size);
			}
			if (colorBuffer != null) {
				colorBuffer.limit(size);
			}
		}

		public void position(int newPosition) {
			if (vertexBuffer != null) {
				vertexBuffer.position(newPosition);
			}
			if (coordsBuffer != null) {
				coordsBuffer.position(newPosition);
			}
			if (colorBuffer != null) {
				colorBuffer.position(newPosition);
			}
		}

		public void dispose() {
			if (vertexBuffer != null) {
				NativeSupport.freeMemory(vertexBuffer);
				this.vertexBuffer = null;
			}
			if (coordsBuffer != null) {
				NativeSupport.freeMemory(coordsBuffer);
				this.coordsBuffer = null;
			}
			if (colorBuffer != null) {
				NativeSupport.freeMemory(colorBuffer);
				this.colorBuffer = null;
			}
		}

	}

	private static final int DEFAULT_MAX_VERTICES = 3000;

	private float[] color = new float[] { 1f, 1f, 1f, 1f };

	private float[] coord = new float[] { 0f, 0f };

	private int count, maxCount;

	private float[] verts = new float[DEFAULT_MAX_VERTICES * 3];

	private float[] cols = new float[DEFAULT_MAX_VERTICES * 4];

	private float[] coords = new float[DEFAULT_MAX_VERTICES * 2];

	public LTexture texture;

	private FloatBuffer vertexBuffer;

	private FloatBuffer coordBuffer;

	private FloatBuffer colorBuffer;

	private float moveX, moveY;

	private int batchType, expand;

	private int ver, col, tex;

	private int texWidth, texHeight;

	private float xOff, yOff, widthRatio, heightRatio;

	private float x1, y1;

	private float x2, y2;

	private float x3, y3;

	private float x4, y4;

	private float[] tmp;

	private float drawWidth, drawHeight;

	private float textureSrcX, textureSrcY;

	private float srcWidth, srcHeight;

	private float renderWidth, renderHeight;

	int oldVertCount, oldColorCount, oldCoordCount;

	boolean useBegin, lockCoord, isColor, isLocked;

	public LTextureBatch(String fileName, Format format) {
		this(fileName, format, DEFAULT_MAX_VERTICES);
	}

	public LTextureBatch(String fileName, Format format, int count) {
		this(LTextures.loadTexture(fileName, format), count);
	}

	public LTextureBatch(String fileName) {
		this(LTextures.loadTexture(fileName), DEFAULT_MAX_VERTICES);
	}

	public LTextureBatch(LTexture texture) {
		this(texture, DEFAULT_MAX_VERTICES);
	}

	public LTextureBatch(String fileName, int count) {
		this(LTextures.loadTexture(fileName), count);
	}

	public LTextureBatch(LTexture texture, int count) {
		this.texture = texture;
		this.texWidth = texture.width;
		this.texHeight = texture.height;
		this.isLocked = false;
		this.make(count);
	}

	public void setTexture(LTexture texture) {
		this.texture = texture;
	}

	private final void glVertex3f(final int count, float x, float y, float z) {
		this.ver = count * 3;
		this.verts[ver + 0] = x;
		this.verts[ver + 1] = y;
		this.verts[ver + 2] = z;
		this.tex = count * 2;
		this.coords[tex + 0] = coord[0];
		this.coords[tex + 1] = coord[1];
		if (!isColor) {
			return;
		}
		this.col = count * 4;
		this.cols[col + 0] = color[0];
		this.cols[col + 1] = color[1];
		this.cols[col + 2] = color[2];
		this.cols[col + 3] = color[3];
	}

	public void glVertex2f(float x, float y) {
		glVertex3f(x, y, 0);
	}

	public void glVertex3f(float x, float y, float z) {
		if (batchType != GL.GL_TRIANGLES) {
			glVertex3f(count, x, y, z);
			count++;
		} else {
			switch (expand) {
			case 0:
				glVertex3f(count, x, y, z);
				glVertex3f(count + 5, x, y, z);
				count++;
				break;
			case 1:
				glVertex3f(count, x, y, z);
				count++;
				break;
			case 2:
				glVertex3f(count, x, y, z);
				glVertex3f(count + 2, x, y, z);
				count++;
				break;
			case 3:
				glVertex3f(count, x, y, z);
				count += 3;
				break;
			}
			expand++;
			if (expand > 3) {
				expand = 0;
			}
			if (count >= maxCount) {
				if (isLimit(count, batchType)) {
					int type = batchType;
					glEnd();
					batchType = type;
				}
			}
		}
	}

	public final void glTexCoord2f(float fcol, float frow) {
		coord[0] = fcol;
		coord[1] = frow;
	}

	public void glColor4f(float r, float g, float b, float a) {
		color[0] = r;
		color[1] = g;
		color[2] = b;
		color[3] = a;
		isColor = true;
	}

	public void glColor4f(LColor c) {
		glColor4f(c.r, c.g, c.b, c.a);
	}

	private boolean isLimit(int count, int type) {
		switch (type) {
		case GL.GL_TRIANGLES:
			return count % 3 == 0;
		case GL.GL_LINES:
			return count % 2 == 0;
		case GL.GL_QUADS:
			return count % 4 == 0;
		}
		return false;
	}

	public void lock() {
		this.isLocked = true;
	}

	public void unLock() {
		this.isLocked = false;
	}

	/**
	 * 开始批处理
	 * 
	 */
	public void glBegin() {
		glBegin(GL10.GL_TRIANGLES);
	}

	/**
	 * 以指定渲染形式开始批处理
	 * 
	 * @param type
	 */
	public void glBegin(int type) {
		this.batchType = type;
		this.useBegin = true;
		this.isColor = false;
		if (!isLocked) {
			this.expand = 0;
			this.count = 0;
		}
	}

	/**
	 * 构建顶点Buffer
	 * 
	 */
	private void make(int size) {
		if (vertexBuffer == null) {
			vertexBuffer = NativeSupport.newFloatBuffer(size * 3);
		}
		if (colorBuffer == null) {
			colorBuffer = NativeSupport.newFloatBuffer(size * 4);
		}
		if (coordBuffer == null) {
			coordBuffer = NativeSupport.newFloatBuffer(size * 2);
		}
		this.maxCount = size;
	}

	/**
	 * 注入顶点数据
	 * 
	 */
	private void insertVertices() {
		if (isLocked) {
			return;
		}
		oldVertCount = count * 3;
		NativeSupport.copy(verts, vertexBuffer, oldVertCount);
		if (isColor) {
			oldColorCount = count * 4;
			NativeSupport.copy(cols, colorBuffer, oldColorCount);
		}
		int size = count * 2;
		if (lockCoord && size == oldCoordCount) {
			return;
		}
		NativeSupport.copy(coords, coordBuffer, size);
		oldCoordCount = size;
	}

	/**
	 * 提交顶点数据到渲染器
	 * 
	 */
	public void glEnd() {
		if (count == 0 || !useBegin) {
			this.useBegin = false;
			return;
		}
		this.insertVertices();
		GLEx.self.glDrawArrays(texture, vertexBuffer, coordBuffer, colorBuffer,
				isColor, count, moveX, moveY);
		this.useBegin = false;
	}

	/**
	 * 提交顶点数据到渲染器，渲染结果用来处理文字
	 * 
	 * @param c
	 */
	public void commitQuad(LColor c, float x, float y, float rotaion) {
		if (count == 0 || !useBegin) {
			this.useBegin = false;
			return;
		}
		this.isColor = false;
		this.insertVertices();
		if (c != null) {
			GLEx.self.setColor(c);
		}
		GLEx.self.glQuad(texture, vertexBuffer, coordBuffer, count, x, y,
				rotaion);
		if (c != null) {
			GLEx.self.setColor(LColor.white);
		}
		this.useBegin = false;
	}

	/**
	 * 提交缓存数据到渲染器，渲染结果用来处理文字
	 * 
	 * @param c
	 */
	public void commitCacheQuad(LColor c, float x, float y, float rotaion) {
		if (count == 0) {
			return;
		}
		if (isLocked) {
			if (c != null) {
				GLEx.self.setColor(c);
			}
			GLEx.self.glQuad(texture, vertexBuffer, coordBuffer, count, x, y,
					rotaion);
			if (c != null) {
				GLEx.self.setColor(LColor.white);
			}
		}
	}

	/**
	 * 提交缓存中的数据
	 * 
	 */
	public void glCacheCommit() {
		if (count == 0) {
			return;
		}
		if (isLocked) {
			GLEx.self.glDrawArrays(texture, vertexBuffer, coordBuffer,
					colorBuffer, isColor, count, moveX, moveY);
		}
	}

	/**
	 * 提交缓存数据
	 * 
	 * @param tex2d
	 * @param cache
	 */
	public final static void commit(LTexture tex2d, GLCache cache) {
		if (cache.count == 0) {
			return;
		}
		GLEx.self.glDrawArrays(tex2d, cache);
	}

	/**
	 * 提交缓存数据进行文字渲染
	 * 
	 * @param tex2d
	 * @param cache
	 * @param c
	 * @param x
	 * @param y
	 */
	public final static void commitQuad(LTexture tex2d, GLCache cache,
			LColor c, float x, float y, float rotation) {
		if (cache.count == 0) {
			return;
		}
		if (c != null) {
			GLEx.self.setColor(c);
		}
		GLEx.self.glQuad(tex2d, cache, x, y, rotation);
		if (c != null) {
			GLEx.self.setColor(LColor.white);
		}
	}

	public void draw(float x, float y) {
		draw(null, x, y, texture.width, texture.height, 0, 0, texture.width,
				texture.height);
	}

	public void draw(float x, float y, float width, float height) {
		draw(null, x, y, width, height, 0, 0, texture.width, texture.height);
	}

	public void draw(float x, float y, float width, float height, float srcX,
			float srcY, float srcWidth, float srcHeight) {
		draw(null, x, y, width, height, srcX, srcY, srcWidth, srcHeight);
	}

	public void draw(LColor[] colors, float x, float y, float width,
			float height) {
		draw(colors, x, y, width, height, 0, 0, texture.width, texture.height);
	}

	/**
	 * 以指定的色彩，顶点绘制出指定区域内的纹理到指定位置
	 * 
	 * @param colors
	 * @param x
	 * @param y
	 * @param width
	 * @param height
	 * @param srcX
	 * @param srcY
	 * @param srcWidth
	 * @param srcHeight
	 */
	public void draw(LColor[] colors, float x, float y, float width,
			float height, float srcX, float srcY, float srcWidth,
			float srcHeight) {
		if (!useBegin) {
			return;
		}
		if (isLocked) {
			return;
		}
		xOff = ((srcX / texWidth) * texture.widthRatio) + texture.xOff;
		yOff = ((srcY / texHeight) * texture.heightRatio) + texture.yOff;
		widthRatio = ((srcWidth / texWidth) * texture.widthRatio);
		heightRatio = ((srcHeight / texHeight) * texture.heightRatio);

		if (colors == null) {
			glTexCoord2f(xOff, yOff);
			glVertex3f(x, y, 0);
			glTexCoord2f(xOff, heightRatio);
			glVertex3f(x, y + height, 0);
			glTexCoord2f(widthRatio, heightRatio);
			glVertex3f(x + width, y + height, 0);
			glTexCoord2f(widthRatio, yOff);
			glVertex3f(x + width, y, 0);
		} else {
			isColor = true;
			glColor4f(colors[LTexture.TOP_LEFT]);
			glTexCoord2f(xOff, yOff);
			glVertex3f(x, y, 0);
			glColor4f(colors[LTexture.BOTTOM_LEFT]);
			glTexCoord2f(xOff, heightRatio);
			glVertex3f(x, y + height, 0);
			glColor4f(colors[LTexture.BOTTOM_RIGHT]);
			glTexCoord2f(widthRatio, heightRatio);
			glVertex3f(x + width, y + height, 0);
			glColor4f(colors[LTexture.TOP_RIGHT]);
			glTexCoord2f(widthRatio, yOff);
			glVertex3f(x + width, y, 0);
		}
	}

	public void drawQuad(float drawX, float drawY, float drawX2, float drawY2,
			float srcX, float srcY, float srcX2, float srcY2) {

		drawWidth = drawX2 - drawX;
		drawHeight = drawY2 - drawY;
		textureSrcX = ((srcX / texWidth) * texture.widthRatio) + texture.xOff;
		textureSrcY = ((srcY / texHeight) * texture.heightRatio) + texture.yOff;
		srcWidth = srcX2 - srcX;
		srcHeight = srcY2 - srcY;
		renderWidth = ((srcWidth / texWidth) * texture.widthRatio);
		renderHeight = ((srcHeight / texHeight) * texture.heightRatio);

		glTexCoord2f(textureSrcX, textureSrcY);
		glVertex3f(drawX, drawY, 0);
		glTexCoord2f(textureSrcX, textureSrcY + renderHeight);
		glVertex3f(drawX, drawY + drawHeight, 0);
		glTexCoord2f(textureSrcX + renderWidth, textureSrcY + renderHeight);
		glVertex3f(drawX + drawWidth, drawY + drawHeight, 0);
		glTexCoord2f(textureSrcX + renderWidth, textureSrcY);
		glVertex3f(drawX + drawWidth, drawY, 0);
	}

	public void draw(Transform2D t) {
		draw(null, texture.width, texture.height, 0, 0, texture.width,
				texture.height, t);
	}

	public void draw(float width, float height, Transform2D t) {
		draw(null, width, height, 0, 0, texture.width, texture.height, t);
	}

	public void draw(float width, float height, float srcX, float srcY,
			float srcWidth, float srcHeight, Transform2D t) {
		draw(null, width, height, srcX, srcY, srcWidth, srcHeight, t);
	}

	public void draw(LColor[] colors, float width, float height, Transform2D t) {
		draw(colors, width, height, 0, 0, texture.width, texture.height, t);
	}

	public void draw(LColor[] colors, float width, float height, float srcX,
			float srcY, float srcWidth, float srcHeight, Transform2D t) {

		if (!useBegin) {
			return;
		}
		if (isLocked) {
			return;
		}

		xOff = ((srcX / texWidth) * texture.widthRatio) + texture.xOff;
		yOff = ((srcY / texHeight) * texture.heightRatio) + texture.yOff;
		widthRatio = ((srcWidth / texWidth) * texture.widthRatio);
		heightRatio = ((srcHeight / texHeight) * texture.heightRatio);

		x1 = 0;
		y1 = 0;

		x2 = 0;
		y2 = height;

		x3 = width;
		y3 = 0;

		x4 = width;
		y4 = height;

		tmp = t.transform(x1, y1, x2, y2, x3, y3, x4, y4);

		if (colors == null) {
			glTexCoord2f(xOff, yOff);
			glVertex3f(tmp[0], tmp[1], 0);
			glTexCoord2f(xOff, heightRatio);
			glVertex3f(tmp[2], tmp[3], 0);
			glTexCoord2f(widthRatio, heightRatio);
			glVertex3f(tmp[6], tmp[7], 0);
			glTexCoord2f(widthRatio, yOff);
			glVertex3f(tmp[4], tmp[5], 0);
		} else {
			isColor = true;
			glColor4f(colors[LTexture.TOP_LEFT]);
			glTexCoord2f(xOff, yOff);
			glVertex3f(tmp[0], tmp[1], 0);
			glColor4f(colors[LTexture.BOTTOM_LEFT]);
			glTexCoord2f(xOff, heightRatio);
			glVertex3f(tmp[2], tmp[3], 0);
			glColor4f(colors[LTexture.BOTTOM_RIGHT]);
			glTexCoord2f(widthRatio, heightRatio);
			glVertex3f(tmp[6], tmp[7], 0);
			glColor4f(colors[LTexture.TOP_RIGHT]);
			glTexCoord2f(widthRatio, yOff);
			glVertex3f(tmp[4], tmp[5], 0);
		}
	}

	public void setImageColor(float r, float g, float b, float a) {
		setColor(LTexture.TOP_LEFT, r, g, b, a);
		setColor(LTexture.TOP_RIGHT, r, g, b, a);
		setColor(LTexture.BOTTOM_LEFT, r, g, b, a);
		setColor(LTexture.BOTTOM_RIGHT, r, g, b, a);
	}

	public void setImageColor(float r, float g, float b) {
		setColor(LTexture.TOP_LEFT, r, g, b);
		setColor(LTexture.TOP_RIGHT, r, g, b);
		setColor(LTexture.BOTTOM_LEFT, r, g, b);
		setColor(LTexture.BOTTOM_RIGHT, r, g, b);
	}

	public void setImageColor(LColor c) {
		if (c == null) {
			return;
		}
		setImageColor(c.r, c.g, c.b, c.a);
	}

	public void setColor(int corner, float r, float g, float b, float a) {
		if (colors == null) {
			colors = new LColor[] { new LColor(1f, 1f, 1f, 1f),
					new LColor(1f, 1f, 1f, 1f), new LColor(1f, 1f, 1f, 1f),
					new LColor(1f, 1f, 1f, 1f) };
		}
		colors[corner].r = r;
		colors[corner].g = g;
		colors[corner].b = b;
		colors[corner].a = a;
	}

	public void setColor(int corner, float r, float g, float b) {
		if (colors == null) {
			colors = new LColor[] { new LColor(1f, 1f, 1f, 1f),
					new LColor(1f, 1f, 1f, 1f), new LColor(1f, 1f, 1f, 1f),
					new LColor(1f, 1f, 1f, 1f) };
		}
		colors[corner].r = r;
		colors[corner].g = g;
		colors[corner].b = b;
	}

	public void draw(float x, float y, LColor[] c) {
		draw(c, x, y, texture.width, texture.height);
	}

	public void draw(float x, float y, LColor c) {
		final boolean update = checkUpdateColor(c);
		if (update) {
			setImageColor(c);
		}
		draw(colors, x, y, texture.width, texture.height);
		if (update) {
			setImageColor(LColor.white);
		}
	}

	public void draw(float x, float y, float width, float height, LColor c) {
		final boolean update = checkUpdateColor(c);
		if (update) {
			setImageColor(c);
		}
		draw(colors, x, y, width, height);
		if (update) {
			setImageColor(LColor.white);
		}
	}

	public void draw(float x, float y, float width, float height, float x1,
			float y1, float x2, float y2, LColor[] c) {
		draw(c, x, y, width, height, x1, y1, x2, y2);
	}

	public void draw(float x, float y, float width, float height, float x1,
			float y1, float x2, float y2, LColor c) {
		final boolean update = checkUpdateColor(c);
		if (update) {
			setImageColor(c);
		}
		draw(colors, x, y, width, height, x1, y1, x2, y2);
		if (update) {
			setImageColor(LColor.white);
		}
	}

	public void draw(float x, float y, float w, float h, float rotation,
			LColor c) {
		draw(x, y, w, h, 0, 0, texture.width, texture.height, rotation, c);
	}

	public void draw(float x, float y, float width, float height, float x1,
			float y1, float x2, float y2, float rotation, LColor c) {
		if (rotation == 0) {
			draw(x, y, width, height, x1, y1, x2, y2, c);
			return;
		}
		final float w = width / 2;
		final float h = height / 2;
		if (transform == null) {
			transform = new Transform2D();
		}
		transform.setToIdentity();
		transform.postTranslate(-w, -h);
		transform.postRotate(rotation);
		transform.postTranslate(w, h);
		transform.postTranslate(x, y);
		draw(x, y, width, height, x1, y1, x2, y2, transform, c);
	}

	public void draw(float x, float y, float width, float height, float x1,
			float y1, float x2, float y2, Transform2D t, LColor c) {
		final boolean update = checkUpdateColor(c);
		if (update) {
			setImageColor(c);
		}
		draw(colors, width, height, x1, y1, x2, y2, t);
		if (update) {
			setImageColor(LColor.white);
		}
	}

	public void draw(Transform2D t, LColor c) {
		final boolean update = checkUpdateColor(c);
		if (update) {
			setImageColor(c);
		}
		draw(colors, texture.width, texture.height, 0, 0, texture.width,
				texture.height, t);
		if (update) {
			setImageColor(LColor.white);
		}
	}

	private boolean checkUpdateColor(LColor c) {
		return c != null && !LColor.white.equals(c);
	}

	public LTexture getTexture() {
		return texture;
	}

	public int getHeight() {
		return texHeight;
	}

	public int getWidth() {
		return texWidth;
	}

	public float getX() {
		return moveX;
	}

	public void setX(float x) {
		this.moveX = x;
	}

	public float getY() {
		return moveY;
	}

	public void setY(float y) {
		this.moveY = y;
	}

	public void setLocation(float x, float y) {
		this.moveX = x;
		this.moveY = y;
	}

	public float[] getCols() {
		return cols;
	}

	public float[] getCoords() {
		return coords;
	}

	public float[] getVerts() {
		return verts;
	}

	public FloatBuffer getColorBuffer() {
		return colorBuffer;
	}

	public FloatBuffer getCoordBuffer() {
		return coordBuffer;
	}

	public FloatBuffer getVertexBuffer() {
		return vertexBuffer;
	}

	public int getOldColorCount() {
		return oldColorCount;
	}

	public int getOldCoordCount() {
		return oldCoordCount;
	}

	public int getOldVertCount() {
		return oldVertCount;
	}

	public boolean isLockCoord() {
		return lockCoord;
	}

	public void setLockCoord(boolean lockCoord) {
		this.lockCoord = lockCoord;
	}

	public void postLastCache() {
		if (lastCache != null) {
			LTextureBatch.commit(texture, lastCache);
		}
	}

	public GLCache getLastCache() {
		return lastCache;
	}

	public GLCache newGLCache(boolean reset) {
		return (lastCache = new GLCache(this, reset));
	}

	public GLCache newGLCache() {
		return newGLCache(false);
	}

	public void disposeLastCache() {
		if (lastCache != null) {
			lastCache.dispose();
			lastCache = null;
		}
	}

	public void destoryAll() {
		dispose();
		destroy();
	}

	public void destroy() {
		if (texture != null) {
			texture.destroy();
		}
	}

	public void dispose() {
		this.count = 0;
		this.useBegin = false;
		this.isLocked = true;
		if (vertexBuffer != null) {
			NativeSupport.freeMemory(vertexBuffer);
			this.vertexBuffer = null;
		}
		if (coordBuffer != null) {
			NativeSupport.freeMemory(coordBuffer);
			this.coordBuffer = null;
		}
		if (colorBuffer != null) {
			NativeSupport.freeMemory(colorBuffer);
			this.colorBuffer = null;
		}
		this.verts = null;
		this.cols = null;
		this.coords = null;
		if (lastCache != null) {
			lastCache.dispose();
			lastCache = null;
		}
		if (colors != null) {
			colors = null;
		}
	}

}
